"""Coordinator module for Miele integration."""

from __future__ import annotations

import asyncio
from collections.abc import Callable
from dataclasses import dataclass
from datetime import timedelta
import logging

from aiohttp import ClientResponseError
from pymiele import MieleAction, MieleAPI, MieleDevice

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


type MieleConfigEntry = ConfigEntry[MieleDataUpdateCoordinator]


@dataclass
class MieleCoordinatorData:
    """Data class for storing coordinator data."""

    devices: dict[str, MieleDevice]
    actions: dict[str, MieleAction]


class MieleDataUpdateCoordinator(DataUpdateCoordinator[MieleCoordinatorData]):
    """Coordinator for Miele data."""

    config_entry: MieleConfigEntry
    new_device_callbacks: list[Callable[[dict[str, MieleDevice]], None]] = []
    known_devices: set[str] = set()
    devices: dict[str, MieleDevice] = {}

    def __init__(
        self,
        hass: HomeAssistant,
        config_entry: MieleConfigEntry,
        api: MieleAPI,
    ) -> None:
        """Initialize the Miele data coordinator."""
        super().__init__(
            hass,
            _LOGGER,
            config_entry=config_entry,
            name=DOMAIN,
            update_interval=timedelta(seconds=120),
        )
        self.api = api

    async def _async_update_data(self) -> MieleCoordinatorData:
        """Fetch data from the Miele API."""
        async with asyncio.timeout(10):
            # Get devices
            devices_json = await self.api.get_devices()
            devices = {
                device_id: MieleDevice(device)
                for device_id, device in devices_json.items()
            }
            self.devices = devices
            actions = {}
            for device_id in devices:
                try:
                    actions_json = await self.api.get_actions(device_id)
                except ClientResponseError as err:
                    _LOGGER.debug(
                        "Error fetching actions for device %s: Status: %s, Message: %s",
                        device_id,
                        err.status,
                        err.message,
                    )
                    actions_json = {}
                except TimeoutError:
                    _LOGGER.debug(
                        "Timeout fetching actions for device %s",
                        device_id,
                    )
                    actions_json = {}
                actions[device_id] = MieleAction(actions_json)
            return MieleCoordinatorData(devices=devices, actions=actions)

    def async_add_devices(self, added_devices: set[str]) -> tuple[set[str], set[str]]:
        """Add devices."""
        current_devices = set(self.devices)
        new_devices: set[str] = current_devices - added_devices

        return (new_devices, current_devices)

    async def callback_update_data(self, devices_json: dict[str, dict]) -> None:
        """Handle data update from the API."""
        devices = {
            device_id: MieleDevice(device) for device_id, device in devices_json.items()
        }
        self.async_set_updated_data(
            MieleCoordinatorData(
                devices=devices,
                actions=self.data.actions,
            )
        )

    async def callback_update_actions(self, actions_json: dict[str, dict]) -> None:
        """Handle data update from the API."""
        actions = {
            device_id: MieleAction(action) for device_id, action in actions_json.items()
        }
        self.async_set_updated_data(
            MieleCoordinatorData(
                devices=self.data.devices,
                actions=actions,
            )
        )
